package gupao.concurrency.threadpool.futures;

import gupao.concurrency.utils.ThreadPoolService;
import gupao.concurrency.utils.Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
public class CompletableFutureTest {
    static Random random = new Random();
    static ThreadPoolExecutor executor = ThreadPoolService.getOrCreateThreadPoolExecutor("price",4,8);
    static PriceService ps = new PriceService();

    public static void main(String[] args) throws Exception {
        futureSample();
        System.out.println();
        completableFutureSample();
    }

    static
    void futureSample() throws Exception {
        log.info("----futureSample----");
        long start = System.currentTimeMillis();
        Future<Double> priceFuture = ps.getPriceAsyncFuture("apple");
        log.info("调用getPriceAsync花了 {} ms", (System.currentTimeMillis() - start));
        doSomethingElse();
        double budget = calcBudget(priceFuture.get());
        log.info("完成任务，总时间： {} ms", (System.currentTimeMillis()-start));
    }
    static
    void completableFutureSample() throws Exception {
        log.info("----completableFutureSample----");
        long start = System.currentTimeMillis();
        CompletableFuture<Double> budgetResult
                = ps.completableFuturePrice("apple")
                    .thenApplyAsync(CompletableFutureTest::calcBudget);
        log.info("getPriceAsyncCompletableFuture {} ms", (System.currentTimeMillis() - start));
        doSomethingElse();
        double budget = budgetResult.get();
        log.info("完成任务，总时间： {} ms", (System.currentTimeMillis()-start));
    }

    static double calcBudget(double price){
        //query quantity
        long quantity = 20;
        Utils.sleepIgnoreExp(800);
        return quantity * price;
    }

    static void doSomethingElse(){
        Utils.sleepIgnoreExp(1200);
    }

    static
    class PriceService {
        public Future<Double> getPriceAsyncFuture(String product){
            return executor.submit(() -> {
                        return calcPrice(product);
                    });
        }
        public CompletableFuture<Double> getPriceAsyncCompletableFuture(String product){
            CompletableFuture<Double> futurePrice = new CompletableFuture<>();
            executor.execute(() -> {
                        double price = calcPrice(product);
                        futurePrice.complete(price);
                    });
            return futurePrice;
        }

        public CompletableFuture<Double> completableFuturePrice(String product){
            return CompletableFuture.supplyAsync(() -> calcPrice(product));
        }
    }

    public static double getPrice(String product){
        return calcPrice(product);
    }

    private static double calcPrice(String product){
        Utils.sleepIgnoreExp(800);
        return random.nextDouble() * product.charAt(0) + product.charAt(1);
    }
}
